﻿//-----------------------------------------------------------------------
// <author>Paul Long</author>
//-----------------------------------------------------------------------

namespace NetworkAddresses
{
    using System;
    using System.Globalization;
    using System.Runtime.InteropServices;
    using Microsoft.NetworkMonitor;
    using TopUserExceptions;
    
    /// <summary>
    /// Ipv4 Address class based on Address
    /// </summary>
    internal class IPv4Address : Address
    {
        /// <summary>
        /// Raw address for IPv4 address.
        /// </summary>
        private uint address;
        
        /// <summary>
        /// Initializes a new instance of the IPv4Address class.
        /// Retrieves the IPv4 information from the frame given the parsed frame and Data field ID.
        /// </summary>
        /// <param name="parsedFrame">Parsed Frame Object handle</param>
        /// <param name="id">Returned ID from NmAddField</param>
        public IPv4Address(IntPtr parsedFrame, uint id)
        {
            NmParsedFieldInfo parsedDataFieldInfo = new NmParsedFieldInfo();
            parsedDataFieldInfo.Size = (ushort)Marshal.SizeOf(typeof(NmParsedFieldInfo));

            uint errno = NetmonAPI.NmGetParsedFieldInfo(parsedFrame, id, (uint)0, ref parsedDataFieldInfo);
            if (errno != 0)
            {
                throw new ParsingException("NmGetParsedField(...) failed, errno = " + errno);
            }

            if (parsedDataFieldInfo.ValueType == FieldType.VT_UINT ||
               parsedDataFieldInfo.ValueType == FieldType.VT_UI4)
            {
                uint value;
                errno = NetmonAPI.NmGetFieldValueNumber32Bit(parsedFrame, id, out value);
                if (errno != 0)
                {
                    throw new ParsingException("NmGetFieldValueNumber32Bit(...) failed, errno = " + errno);
                }

                this.address = value;

                Display = String.Format(CultureInfo.CurrentCulture, "{0}.{1}.{2}.{3}", (this.address >> 24) & 0xFF, (this.address >> 16) & 0xFF, (this.address >> 8) & 0xFF, this.address & 0xFF);
            }
            else
            {
                this.address = 0;
            }
        }
        
        /// <summary>
        /// Compares two IPv4 address for equality.
        /// </summary>
        /// <param name="leftOperand">The first ethernet address.</param>
        /// <param name="rightOperand">The second ethernet address.</param>
        /// <returns>True if equal.</returns>
        public static bool operator ==(IPv4Address leftOperand, IPv4Address rightOperand)
        {
            if ((object)leftOperand == null || (object)rightOperand == null)
            {
                return false;
            }

            if ((object)leftOperand.address == null || (object)rightOperand.address == null)
            {
                return false;
            }

            if (leftOperand.address == rightOperand.address)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// Compares two IPv4 address for inequality.
        /// </summary>
        /// <param name="leftOperand">The first ethernet address.</param>
        /// <param name="rightOperand">The second ethernet address.</param>
        /// <returns>True if not equal.</returns>
        public static bool operator !=(IPv4Address leftOperand, IPv4Address rightOperand)
        {
            if ((object)leftOperand == null || (object)rightOperand == null)
            {
                return false;
            }

            if ((object)leftOperand.address == null || (object)rightOperand.address == null)
            {
                return false;
            }

            if (leftOperand.address != rightOperand.address)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// Compares two IPv4 address for greater than.
        /// </summary>
        /// <param name="leftOperand">The first ethernet address.</param>
        /// <param name="rightOperand">The second ethernet address.</param>
        /// <returns>True if greater than.</returns>
        public static bool operator >(IPv4Address leftOperand, IPv4Address rightOperand)
        {
            if ((object)leftOperand == null || (object)rightOperand == null)
            {
                return false;
            }

            if (leftOperand.address > rightOperand.address)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// Compares two IPv4 address for less than.
        /// </summary>
        /// <param name="leftOperand">The first ethernet address.</param>
        /// <param name="rightOperand">The second ethernet address.</param>
        /// <returns>True if less than.</returns>
        public static bool operator <(IPv4Address leftOperand, IPv4Address rightOperand)
        {
            if ((object)leftOperand == null || (object)rightOperand == null)
            {
                return false;
            }

            if (leftOperand.address < rightOperand.address)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// Checks if IPv4 address is valid.
        /// </summary>
        /// <returns>True is address is valid.</returns>
        public bool IsValid()
        {
            if (this.address != 0)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// Equality for IPv4
        /// </summary>
        /// <param name="obj">Object to compare to.</param>
        /// <returns>True if objects are equal</returns>
        public override bool Equals(object obj)
        {
            return (IPv4Address)obj == this;
        }

        /// <summary>
        /// Gets the hash code for equality..
        /// </summary>
        /// <returns>Returns hash code</returns>
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }
    }
}
